package service

import (
	"admin100/app/dao"
	"admin100/app/model"
	"admin100/app/model/commonmodel"
	"admin100/app/model/commonmodel/userEnum"
	"admin100/library/define/defErr"
	"admin100/library/utils"
	"database/sql"
	"strings"
	"time"

	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/util/gconv"

	"admin100/library/define"
	"math"

	"github.com/gogf/gf/frame/g"
)

var User = userService{}

type userService struct{}

// 获取用户清单
func (s *userService) List(page int, numsPerPage int) (pageInfo commonmodel.PageInfo, data []*model.MyadminUser, err error) {
	var nums int
	nums, err = dao.MyadminUser.Count()
	if err != nil {
		return commonmodel.PageInfo{}, nil, err
	}

	pageInfo = commonmodel.PageInfo{
		Total: nums,
		Cur:   page,
		PNum:  int(math.Ceil(float64(nums) / float64(numsPerPage))),
	}

	//
	data, err = dao.MyadminUser.Page(page, numsPerPage).All()
	if err != nil {
		return commonmodel.PageInfo{}, nil, err
	}

	return pageInfo, data, nil
}

func (s *userService) Add(data *model.MyadminUserServiceAddData) bool {

	// 用户名唯一性检测
	if has := dao.MyadminUser.IsExistUsername(data.Name); has {
		defErr.Panic(define.NameExist)
	}

	// 帐户名唯一性检测
	if has := dao.MyadminUser.IsExistAccount(data.Account); has {
		defErr.Panic(define.AccountExist)
	}

	//简单加盐加密

	data.Password = utils.Md5Direct(data.Password)
	if r, err := dao.MyadminUser.Save(data); err != nil {
		defErr.Panic(define.DataOptFail)
	} else {
		if data.Id, err = r.LastInsertId(); err != nil {
			defErr.Panic(define.DataOptFail)
		}
	}

	return true
}

// 添加角色关联
func (s *userService) AddRoleRel(uid int64, roleId string) bool {
	arrRoleIds := strings.Split(roleId, ",")
	if len(arrRoleIds) > 0 && len(arrRoleIds[0]) == 0 {
		defErr.Panic(define.RoleNotExist)
	}

	// delete now rel about role
	if _, err := dao.MyadminRoleUserRel.Delete(dao.MyadminRoleUserRel.Columns.Id, roleId); err != nil {
		defErr.Panic(define.DataOptFail)
	}

	nowTime := gtime.New(time.Now())
	inList := g.List{}
	for _, roleId := range arrRoleIds {
		inList = append(inList, map[string]interface{}{
			dao.MyadminRoleUserRel.Columns.UserId:  uid,
			dao.MyadminRoleUserRel.Columns.RoleId:  roleId,
			dao.MyadminRoleUserRel.Columns.Created: nowTime,
		})
	}

	if _, err := dao.MyadminRoleUserRel.DB.BatchInsert(dao.MyadminRoleUserRel.Table, inList); err != nil {
		defErr.Panic(define.DataOptFail)
	}

	return true
}

// 删除用户
func (s *userService) Del(uid int64) bool {

	if uid < 1 {
		return true
	}

	if _, err := dao.MyadminUser.Delete(dao.MyadminUser.Columns.Id, uid); err != nil {
		defErr.Panic(define.DataOptFail)
	}

	return true
}

// 更新用户数据
func (s *userService) Edit(data *model.MyadminUserServiceAddData) bool {

	u := s.FetchUserByUid(data.Id)

	if u.Name != data.Name {
		// 用户名唯一性检测
		if has := dao.MyadminUser.IsExistUsername(data.Name); has {
			defErr.Panic(define.NameExist)
		}
	}

	if u.Account != data.Account {
		// 帐户名唯一性检测
		if has := dao.MyadminUser.IsExistAccount(data.Account); has {
			defErr.Panic(define.AccountExist)
		}
	}

	if len(data.Password) > 0 {
		data.Password = utils.DoubleMd5(data.Password)
	} else {
		data.Password = u.Password
	}

	if _, err := dao.MyadminUser.Save(data); err != nil {
		defErr.Panic(define.DataOptFail)
	}

	return true
}

//
func (s *userService) SetCanLogTimes(user *model.MyadminUser) {
	user.ContinueLoginErrorTimes += 1
	if user.ContinueLoginErrorTimes >= 5 {
		user.CanLoginTime = int(gtime.Timestamp()) + 180
	}

	if _, err := dao.MyadminUser.Where(dao.MyadminUser.Columns.Id, user.Id).Update(user); err != nil {
		defErr.Panic(define.DataOptFail)
	}
}

// 获取用户by account
func (s *userService) FetchUserByAccount(account string) *model.MyadminUser {

	r, err := dao.MyadminUser.FindOne(dao.MyadminUser.Columns.Account, account)
	if err == sql.ErrNoRows {
		defErr.Panic(define.UserNotExist)
	}
	defErr.IfPanic(err, define.DataOptFail)

	return r
}

// 获取用户by uid
func (s *userService) FetchUserByUid(uid int64) *model.MyadminUser {

	r, err := dao.MyadminUser.FindOne(dao.MyadminUser.Columns.Id, uid)
	defErr.IfPanic(err, define.DataOptFail)
	if r == nil {
		defErr.Panic(define.UserNotExist)
	}

	return r
}

// 获取角色by uid
func (s *userService) FetchRoleByUid(uid int64) []map[string]string {

	var (
		AliasRel  = "REL"
		AliasRole = "ROLE"
		roleId    = AliasRole + "." + dao.MyadminRole.Columns.Id
		relRoleId = AliasRel + "." + dao.MyadminRoleUserRel.Columns.RoleId
		relUserId = AliasRel + "." + dao.MyadminRoleUserRel.Columns.UserId
		roleName  = AliasRole + "." + dao.MyadminRole.Columns.Name
	)
	r, err := g.Model(dao.MyadminRoleUserRel.Table).As(AliasRel).Safe().LeftJoin(dao.MyadminRole.Table+" "+AliasRole, roleId+" = "+relRoleId).
		Fields(relRoleId, roleName).
		Where(relUserId, uid).All()
	defErr.IfPanic(err, define.DataOptFail)

	var res []map[string]string
	for _, v := range r {
		res = append(res, map[string]string{"role_id": v["role_id"].String(), "name": v["name"].String()})
	}

	return res
}

// 用户登录后状态字段设置
func (s *userService) SetSomeFieldsAfterLogin(ip string, user *model.MyadminUser) {
	user.LastLoginIp = ip
	user.LastLoginTime = int(gtime.Timestamp())
	user.ContinueLoginErrorTimes = 0
	user.LoginTimes += 1
	if _, err := dao.MyadminUser.Where(dao.MyadminUser.Columns.Id, user.Id).Update(user); err != nil {
		defErr.Panic(define.DataOptFail)
	}
}

func (s *userService) GetSimpleList() interface{} {

	r, err := g.Model(dao.MyadminUser.Table).
		Where(dao.MyadminUser.Columns.Status, userEnum.Enabled).
		Fields(dao.MyadminUser.Columns.Id, dao.MyadminUser.Columns.Name).All()
	defErr.IfPanic(err, define.DataOptFail)

	return r
}

func (s *userService) FetchLoginAdminLogList(req *model.LoginAdminReq) ([]*model.LoginAdminLog, int) {

	var columns = dao.LoginAdminLog.Columns

	m := dao.LoginAdminLog.WhereValNotEmpty(g.Map{
		columns.Account: req.Account,
		columns.Ip:      req.Ip,
		columns.State:   req.State,
	})
	m1 := m.Clone()

	data, err := m.Page(req.Cur, req.PNum).Order(columns.Id + " asc").FindAll()
	defErr.SelectRetPanic(err, data, define.DataOptFail)

	total, err := m1.Count()
	if err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}

	return data, total
}

func (s *userService) FetchRequestLogList(req *model.RequestAdminReq) ([]*model.RequestAdminLog, int) {

	var columns = dao.RequestAdminLog.Columns
	m := dao.RequestAdminLog.WhereValNotEmpty(g.Map{
		columns.UserId:    req.UserId,
		columns.Url:       req.Url,
		columns.LoginType: req.LoginType,
	})
	if req.StartTime > 0 {
		m = m.Where(columns.ChangeTime+" between ? and ?", g.Slice{req.StartTime, req.EndTime})
	}
	m1 := m.Clone()

	data, err := m.Page(req.Cur, req.PNum).Order(columns.Id + " asc").FindAll()
	defErr.SelectRetPanic(err, data, define.DataOptFail)

	total, err := m1.Count()
	if err != nil {
		defErr.Panic(define.DataOptFail, err.Error())
	}
	var ids []int
	for _, v := range data {
		ids = append(ids, v.UserId)
	}
	utils.RemoveReIntData(ids)
	uData := dao.MyadminUser.GetUserIdsMap(ids)
	for _, e := range data {
		if tmpUser, ok := uData[int(e.UserId)]; ok {
			e.UserName = tmpUser.Name
		} else {
			e.UserName = "不存在" + gconv.String(e.UserId)
		}
	}

	return data, total
}
